﻿//+-------------------------------------------------------------------------------------------------------------------------------------------------------
//
//Description: ScriptApplicationViewModel
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Input;
using VmroleAuthor.Commands;
using VmroleAuthor.Models;

namespace VmroleAuthor.ViewModels
{
    public class ScriptApplicationViewModel : TreeViewItemViewModel, IAddScriptCommand, IDataErrorInfo, IProduceValidationResults, IRemoveChildItem, ICanBeRemovedFromTree
    {
        private readonly VmRoleResourceExtensionViewModel vmRoleResourceExtensionViewModel;
        private readonly ScriptApplication scriptApplication;
        private readonly ObservableCollection<EnvironmentVariableViewModel> environmentVariableViewModels;

        private ReferencedApplicationPayloadViewModel scriptAppPackage;

        private StringParameterizableProperty deploymentName;
        private BoolParameterizableProperty alwaysReboot;    
        private EnumParameterizableProperty errorPolicy;
        private StringParameterizableProperty executable;
        private StringParameterizableProperty parameters;
        private StringParameterizableProperty exitCodeRegex;
        private IntParameterizableProperty maxOutputSize;
        private StringParameterizableProperty rebootExitCodeRegex;
        private BoolParameterizableProperty restartOnExitCodeReboot;        
        private StringParameterizableProperty scriptBlock;    
        private CredentialParameterizableProperty scriptCredential;
        private StringParameterizableProperty standardErrorPath;
        private StringParameterizableProperty standardErrorRegex;
        private StringParameterizableProperty standardInput;
        private StringParameterizableProperty standardOutputPath;
        private StringParameterizableProperty standardOutputRegex;
        private IntParameterizableProperty timeoutInSeconds;
        private StringParameterizableProperty workingDirectory;
           

        public static class PropertyNames
        {
            public const string Summary = "Summary";            
            public const string ScriptAppPackage = "ScriptAppPackage";
            public const string EnvironmentVariables = "EnvironmentVariables"; 
            public const string DeploymentName = "DeploymentName";
            public const string AlwaysReboot = "AlwaysReboot";            
            public const string ErrorPolicy = "ErrorPolicy";
            public const string Executable = "Executable";
            public const string Parameters = "Parameters";
            public const string ExitCodeRegex = "ExitCodeRegex";
            public const string MaxOutputSize = "MaxOutputSize";
            public const string RebootExitCodeRegex = "RebootExitCodeRegex";
            public const string RestartOnExitCodeReboot = "RestartOnExitCodeReboot";
            public const string ScriptBlock = "ScriptBlock";         
            public const string ScriptCredential = "ScriptCredential";
            public const string StandardErrorPath = "StandardErrorPath";
            public const string StandardErrorRegex = "StandardErrorRegex";
            public const string StandardInput = "StandardInput";
            public const string StandardOutputPath = "StandardOutputPath";
            public const string StandardOutputRegex = "StandardOutputRegex";
            public const string TimeoutInSeconds = "TimeoutInSeconds";
            public const string WorkingDirectory = "WorkingDirectory";
        }

        public ScriptApplicationViewModel(
            ScriptApplication scriptApplication,
            ApplicationProfileViewModel applicationProfileViewModel,
            VmRoleResourceExtensionViewModel resourceExtensionViewModel)
            : base(applicationProfileViewModel, true)
        {
            if (scriptApplication == null)
            {
                scriptApplication = new ScriptApplication();
            }
            this.scriptApplication = scriptApplication;
            this.vmRoleResourceExtensionViewModel = resourceExtensionViewModel;

            this.environmentVariableViewModels = new ObservableCollection<EnvironmentVariableViewModel>();
            if (this.scriptApplication.EnvironmentVariables != null)
            {
                foreach (EnvironmentVariable environmentVariable in this.scriptApplication.EnvironmentVariables)
                {
                    this.environmentVariableViewModels.Add(new EnvironmentVariableViewModel(environmentVariable, this.vmRoleResourceExtensionViewModel));                  
                }
            }  

            this.AddEnvironmentVariableCommand = new RelayCommand(
             param => this.AddEnvironmentVariable(),
             param => this.CanAddEnvironmentVariable());

            this.DeleteEnvironmentVariableCommand = new RelayCommand(
                param => this.DeleteEnvironmentVariable((EnvironmentVariableViewModel)param),
                param => this.CanDeleteEnvironmentVariable((EnvironmentVariableViewModel)param));    
            
            this.ValidationResults = new ObservableCollection<CloudServiceModelValidationResult>();
        }

        public ScriptApplication ScriptApplication
        {
            get { return this.scriptApplication; }
        }

        public string Summary
        {
            get
            {
               if (string.IsNullOrEmpty(this.scriptApplication.DeploymentName))
               {
                   return "Script Application";
               }
               return "Script Application (" + this.scriptApplication.DeploymentName + ")";
            }
        }

        public ReferencedApplicationPayloadViewModel ScriptAppPackage
        {
            get
            {
                if (this.scriptAppPackage == null)
                {
                    Func<string> getter = () => this.scriptApplication.ApplicationPayloadId;
                    Action<string> setter = delegate(string value) { this.scriptApplication.ApplicationPayloadId = value; };
                    this.scriptAppPackage = new ReferencedApplicationPayloadViewModel(this.vmRoleResourceExtensionViewModel, ValidationHelper.PayloadType.ScriptFolder, getter, setter, false, PropertyNames.ScriptAppPackage);
                }
                return this.scriptAppPackage;
            }
        }

        public ObservableCollection<EnvironmentVariableViewModel> EnvironmentVariables
        {
            get { return this.environmentVariableViewModels; }
        }

        public StringParameterizableProperty DeploymentName
        {
            get
            {
                if (this.deploymentName == null)
                {
                    if (this.scriptApplication.ExecutableAndParams == null)
                    {
                        this.scriptApplication.ExecutableAndParams = new ExecutableAndParams();
                    }
                    Func<string> paramValueGetter = () => this.scriptApplication.DeploymentName;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.DeploymentName = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.DeploymentName;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Deployment name"
                    };

                    this.deploymentName = new StringParameterizableProperty(
                        PropertyNames.DeploymentName,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Deployment name",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.deploymentName;
            }          
        }


        /// <summary>
        /// bool
        /// </summary>   
        public BoolParameterizableProperty AlwaysReboot
        {
            get
            {
                if (this.alwaysReboot == null)
                {
                    Func<string> paramValueGetter = () =>
                        {
                            if (string.IsNullOrEmpty(this.scriptApplication.AlwaysReboot))
                            {
                                this.scriptApplication.AlwaysReboot = "false";
                            }
                            return this.scriptApplication.AlwaysReboot;
                        };
                        
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.AlwaysReboot = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.AlwaysReboot;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Boolean,
                        DefaultInitialValue = "false",
                        DefaultEnglishLabelText = "Always reboot"
                    };

                    this.alwaysReboot = new BoolParameterizableProperty(
                        PropertyNames.AlwaysReboot,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Boolean,
                        "Script Application Always Reboot",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.alwaysReboot;
            }
        }
   

        /// <summary>
        /// ProvisioningScriptExecutionPolicy 
        /// </summary>
        public EnumParameterizableProperty ErrorPolicy
        {
            get
            {
                if (this.errorPolicy == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.ErrorPolicy;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.ErrorPolicy = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ErrorPolicy;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Option,
                        Options = new List<string>(Enum.GetNames(typeof(ProvisioningScriptExecutionPolicy))),
                        DefaultEnglishLabelText = "Error policy",
                        DefaultInitialValue = ProvisioningScriptExecutionPolicy.FailOnMatch.ToString()
                    };

                    this.errorPolicy = new EnumParameterizableProperty(
                        PropertyNames.ErrorPolicy,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application ErrorPolicy",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        typeof(ProvisioningScriptExecutionPolicy),
                        true,
                        viewDefParamInfo);
                }
                return this.errorPolicy;
            }
        }



        public StringParameterizableProperty Executable
        {
            get
            {
                if (this.executable == null)
                {
                    if (this.scriptApplication.ExecutableAndParams == null)
                    {
                        this.scriptApplication.ExecutableAndParams = new ExecutableAndParams();
                    }
                    Func<string> paramValueGetter = () => this.scriptApplication.ExecutableAndParams != null ? this.scriptApplication.ExecutableAndParams.Executable : null;
                    Action<string> paramValueSetter = delegate(string value)
                        {
                            if (this.scriptApplication.ExecutableAndParams == null)
                            {
                                this.scriptApplication.ExecutableAndParams = new ExecutableAndParams();
                            }
                            this.scriptApplication.ExecutableAndParams.Executable = value;
                        };
                    Func<string> autoParamNameGetter = () => PropertyNames.Executable;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Executable"
                    };

                    this.executable = new StringParameterizableProperty(
                        PropertyNames.Executable,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application Executable",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.executable;
            }
        }


        public StringParameterizableProperty Parameters
        {
            get
            {
                if (this.parameters == null)
                {
                    if (this.scriptApplication.ExecutableAndParams == null)
                    {
                        this.scriptApplication.ExecutableAndParams = new ExecutableAndParams();
                    }
                    Func<string> paramValueGetter = () => this.scriptApplication.ExecutableAndParams != null ? this.scriptApplication.ExecutableAndParams.Parameters : null;
                    Action<string> paramValueSetter = delegate(string value)
                        {
                            if (this.scriptApplication.ExecutableAndParams == null)
                            {
                                this.scriptApplication.ExecutableAndParams = new ExecutableAndParams();
                            }
                            this.scriptApplication.ExecutableAndParams.Parameters = value;
                        };
                    Func<string> autoParamNameGetter = () => PropertyNames.Parameters;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Executable Parameters"
                    };

                    this.parameters = new StringParameterizableProperty(
                        PropertyNames.Parameters,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application Executable Parameters",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.parameters;
            }
        }

        public StringParameterizableProperty ExitCodeRegex
        {
            get
            {
                if (this.exitCodeRegex == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.ExitCodeRegex;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.ExitCodeRegex = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ExitCodeRegex;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "ExitCode Regex",
                        DefaultInitialValue = "[[1-9][[0-9]*"
                    };

                    this.exitCodeRegex = new StringParameterizableProperty(
                        PropertyNames.ExitCodeRegex,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application ExitCodeRegex",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo
                        );
                }
                return this.exitCodeRegex;
            }
        }


        public IntParameterizableProperty MaxOutputSize
        {
            get
            {
                if (this.maxOutputSize == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.MaxOutputSize;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.MaxOutputSize = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.MaxOutputSize;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultEnglishLabelText = "Max Output Size",
                        DefaultInitialValue = "1048576"
                    };

                    this.maxOutputSize = new IntParameterizableProperty(
                        PropertyNames.MaxOutputSize,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "Script application MaxOutputSize",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo
                        );
                }
                return this.maxOutputSize;
            }
        }


        public StringParameterizableProperty RebootExitCodeRegex
        {
            get
            {
                if (this.rebootExitCodeRegex == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.RebootExitCodeRegex;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.RebootExitCodeRegex = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.RebootExitCodeRegex;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Reboot ExitCode Regex",
                        DefaultInitialValue = "{1641}|{3010}|{3011}"
                    };

                    this.rebootExitCodeRegex = new StringParameterizableProperty(
                        PropertyNames.RebootExitCodeRegex,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application RebootExitCodeRegex",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.rebootExitCodeRegex;
            }
        }


        public BoolParameterizableProperty RestartOnExitCodeReboot
        {
            get
            {
                if (this.restartOnExitCodeReboot == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.RestartOnExitCodeReboot;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.RestartOnExitCodeReboot = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.RestartOnExitCodeReboot;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Boolean,
                        DefaultInitialValue = "false",
                        DefaultEnglishLabelText = "Restart On Exit Code Reboot"
                    };

                    this.restartOnExitCodeReboot = new BoolParameterizableProperty(
                        PropertyNames.RestartOnExitCodeReboot,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Boolean,
                        "Script Application Restart On Exit Code Reboot",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.restartOnExitCodeReboot;            
            }
        }

        public StringParameterizableProperty ScriptBlock
        {
            get
            {
                if (this.scriptBlock == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.ScriptBlock;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.ScriptBlock = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ScriptBlock;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.MultiLineString,
                        DefaultEnglishLabelText = "Script Command Script Block"
                    };

                    this.scriptBlock = new StringParameterizableProperty(
                        PropertyNames.ScriptBlock,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application ScriptBlock",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.scriptBlock;
            }
        }
       

        public CredentialParameterizableProperty ScriptCredential
        {
            get
            {
                if (this.scriptCredential == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.ScriptCredential;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.ScriptCredential = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.ScriptCredential;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Credential,
                        DefaultEnglishLabelText = "Script Command Credential"
                    };

                    this.scriptCredential = new CredentialParameterizableProperty(
                        PropertyNames.ScriptCredential,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Credential,
                        "Script application ScriptCredential",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.scriptCredential;
            }
        }

        public StringParameterizableProperty StandardErrorPath
        {
            get
            {
                if (this.standardErrorPath == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.StandardErrorPath;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.StandardErrorPath = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.StandardErrorPath;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Standard error path",
                        DefaultInitialValue = "c:\\err.txt"
                    };

                    this.standardErrorPath = new StringParameterizableProperty(
                        PropertyNames.StandardErrorPath,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application StandardErrorPath",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.standardErrorPath;
            }
        }


        public StringParameterizableProperty StandardErrorRegex
        {
            get
            {
                if (this.standardErrorRegex == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.StandardErrorRegex;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.StandardErrorRegex = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.StandardErrorRegex;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Standard error regex",
                        DefaultInitialValue = ".+"
                    };

                    this.standardErrorRegex = new StringParameterizableProperty(
                        PropertyNames.StandardErrorRegex,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application StandardErrorRegex",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.standardErrorRegex;
            }
        }

        public StringParameterizableProperty StandardInput
        {
            get
            {
                if (this.standardInput == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.StandardInput;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.StandardInput = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.StandardInput;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Standard input"
                    };

                    this.standardInput = new StringParameterizableProperty(
                        PropertyNames.StandardInput,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application standard input",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.standardInput;
            }
        }

        public StringParameterizableProperty StandardOutputPath
        {
            get
            {
                if (this.standardOutputPath == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.StandardOutputPath;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.StandardOutputPath = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.StandardOutputPath;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Standard output path",
                        DefaultInitialValue = "c:\\out.txt"
                    };

                    this.standardOutputPath = new StringParameterizableProperty(
                        PropertyNames.StandardOutputPath,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application StandardOutputPath",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.standardOutputPath;
            }
        }

        public StringParameterizableProperty StandardOutputRegex
        {
            get
            {
                if (this.standardOutputRegex == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.StandardOutputRegex;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.StandardOutputRegex = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.StandardOutputRegex;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Standard output regex"
                    };

                    this.standardOutputRegex = new StringParameterizableProperty(
                        PropertyNames.StandardOutputRegex,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application Standard Output Regex",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.standardOutputRegex;
            }
        }


        public IntParameterizableProperty TimeoutInSeconds
        {
            get
            {
                if (this.timeoutInSeconds == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.TimeoutInSeconds;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.TimeoutInSeconds = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.TimeoutInSeconds;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultEnglishLabelText = "Timeout in seconds",
                        DefaultInitialValue = 5000.ToString(CultureInfo.InvariantCulture)
                    };

                    this.timeoutInSeconds = new IntParameterizableProperty(
                        PropertyNames.TimeoutInSeconds,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "Script application TimeoutInSeconds",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.timeoutInSeconds;
            }
        }

        public StringParameterizableProperty WorkingDirectory
        {
            get
            {
                if (this.workingDirectory == null)
                {
                    Func<string> paramValueGetter = () => this.scriptApplication.WorkingDirectory;
                    Action<string> paramValueSetter = delegate(string value) { this.scriptApplication.WorkingDirectory = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.WorkingDirectory;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Working directory"
                    };

                    this.workingDirectory = new StringParameterizableProperty(
                        PropertyNames.StandardOutputRegex,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Script application WorkingDirectory",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.workingDirectory;
            }
        }            



        public ICommand AddEnvironmentVariableCommand
        {
            get;
            private set;
        }

        public ICommand DeleteEnvironmentVariableCommand
        {
            get;
            private set;
        }

        public bool CanAddEnvironmentVariable()
        {
            return true;
        }

        public void AddEnvironmentVariable()
        {
            EnvironmentVariable env = new EnvironmentVariable();
            if (this.scriptApplication.EnvironmentVariables == null)
            {
                this.scriptApplication.EnvironmentVariables = new List<EnvironmentVariable>();
            }
            this.scriptApplication.EnvironmentVariables.Add(env);
            var environmentVariableViewModel = new EnvironmentVariableViewModel(env, this.vmRoleResourceExtensionViewModel);
            this.environmentVariableViewModels.Add(environmentVariableViewModel);           
        }

        public bool CanDeleteEnvironmentVariable(EnvironmentVariableViewModel environmentVariableViewModel)
        {
            return true;
        }

        public void DeleteEnvironmentVariable(EnvironmentVariableViewModel environmentVariableViewModel)
        {
            if (environmentVariableViewModel != null)
            {
                environmentVariableViewModel.Cleanup();
                if (this.scriptApplication.EnvironmentVariables != null)
                {
                    this.scriptApplication.EnvironmentVariables.Remove(environmentVariableViewModel.EnvironmentVariable);
                }
                this.environmentVariableViewModels.Remove(environmentVariableViewModel);                 
            }                      
        }

        public bool CanAddScriptCommand
        {
            get { return true; }
        }

        public void AddScriptCommand()
        {
            this.IsExpanded = true;
            if (this.scriptApplication.ScriptCommands == null)
            {
                this.scriptApplication.ScriptCommands = new List<ProvisioningScript>();
            }

            ProvisioningScript scriptCommand = new ProvisioningScript();
            scriptCommand.ExecutableAndParams = new ExecutableAndParams();
            this.scriptApplication.ScriptCommands.Add(scriptCommand);
            var scriptCommandViewModel = new ProvisioningScriptViewModel(scriptCommand, this, this.vmRoleResourceExtensionViewModel);
            this.Children.Add(scriptCommandViewModel);
            scriptCommandViewModel.IsSelected = true;
        }

        protected override void LoadChildren()
        {
            if (this.scriptApplication.ScriptCommands != null)
            {
                foreach (ProvisioningScript provisioningScript in this.scriptApplication.ScriptCommands)
                {
                    this.Children.Add(new ProvisioningScriptViewModel(provisioningScript, this, this.vmRoleResourceExtensionViewModel));
                }
            }                         
        }

        public void RemoveChild(TreeViewItemViewModel childItem)
        {
            var provisioningScriptViewModel = childItem as ProvisioningScriptViewModel;
            if (provisioningScriptViewModel != null)
            {
                provisioningScriptViewModel.Cleanup();
                this.scriptApplication.ScriptCommands.Remove(provisioningScriptViewModel.ProvisioningScript);
                this.Children.Remove(childItem);
            }
        }

        public void Cleanup()
        {
            this.IsExpanded = true;
            ParametersAndPayloadCleanupHelper.CleanupParametersAndPayload(this, typeof(PropertyNames));
        }

        public string this[string propertyName]
        {
            get
            {
                string error = null;
                switch (propertyName)
                {
                    case PropertyNames.ScriptBlock:                
                        if (this.scriptBlock != null && this.scriptBlock.PropertyValue != null &&
                            ((this.executable != null && this.executable.PropertyValue != null) || (this.parameters != null && this.parameters.PropertyValue != null)))
                        {
                            error = "Cannot specify both ScriptBlock and Executable/Parameters";
                        }
                        else if (this.scriptBlock != null && this.scriptBlock.PropertyValue == null && (this.executable != null && this.executable.PropertyValue == null))
                        {
                            error = "Must specify either ScriptBlock or Executable/Parameters";
                        }
                        break; 
                    case PropertyNames.DeploymentName:
                        error = ValidationHelper.ValidateNotNullOrEmpty(this.scriptApplication.DeploymentName) ??
                               ValidationHelper.ValidateApplicationDeploymentNamesAreUnique(this.vmRoleResourceExtensionViewModel.ResourceExtensionDefinition);
                        break;
                }
                return error;                
            }           
        }

        public string Error { get; set; }

        public ObservableCollection<CloudServiceModelValidationResult> ValidationResults { get; private set; }

        public void UpdateValidationResults()
        {
            this.IsExpanded = true;
            ModelValidationResultsHelper.UpdateValidationResults(this, typeof(PropertyNames));
            //Add any other cross-field validations error            
        }    
    }
}
